﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Spinning.Spinning.Unitity;
using Microsoft.Xna.Framework;
using Microsoft.Devices.Sensors;
using System.Net;
using Spinning.Spinning.Entity.Battle;
using Box2D.XNA;
using Spinning.Spinning.UI;

namespace Spinning.Spinning.Entity.Scenes
{
    class HostScene : BaseScene
    {
        public World World { get; protected set; }
        public ActorContactManager contactManager { get; protected set; }
        public PhysicConnectManager PhysicConnectManager { get; protected set; }
        Vector3 _accelReading = new Vector3();
        Vector3 _accelReadingEnemy = new Vector3();
        BattlePlayer Player, Enemy;
        private UdpAnySourceMulticastChannel Channel { get; set; }
        TextEntity te;
        String _packetInfo = "";
        protected StatusBar bar;
        WindowBound b;

        public HostScene()
            : base()
        {
            PhysicConnectManager = new PhysicConnectManager();
            contactManager = new ActorContactManager(PhysicConnectManager);
            Vector2 gravity;
            gravity = new Vector2(0f, 0f);
            bool doSleep = false;
            World = new World(gravity, doSleep);
            World.ContactListener = contactManager;

            Game1._acceleMeter.CurrentValueChanged += GSensorChanged;
            try
            {
                Game1._acceleMeter.Start();
            }
            catch (AccelerometerFailedException e) { throw e; }
            catch (UnauthorizedAccessException e) { throw e; }
        }

        void GSensorChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
        {
            _accelReading.X = (float)e.SensorReading.Acceleration.X;
            _accelReading.Y = -(float)e.SensorReading.Acceleration.Y;
            _accelReading.Z = (float)e.SensorReading.Acceleration.Z;
        }

        public override void OnLoad()
        {
            base.OnLoad();

            int fullLife = Game1.stageManager.LifeTimeEarnByUser * 5;
            int enemyFullLife = Game1.stageManager.BattleData.EnemyLifeTimeEarn * 5;

            if (Game1.stageManager.GameSrate.CurrentPlayer == Constants.PlayerId.Omega) fullLife += 25;
            if (Game1.stageManager.BattleData.CurrentEnemy == Constants.PlayerId.Omega) enemyFullLife += 25;

            Sprite backGroundSprite = new Sprite();
            backGroundSprite.textureName = "bg";
            backGroundSprite.ZIndex = Constants.background;
            backGroundSprite.OnLoad();
            this.Attach(backGroundSprite);

            Player = new BattlePlayer();
            Player.textureName = "spinning";
            Player.OnLoad();
            Player.LifeTime = fullLife;
            Player.SetAnimation(Constants.playerAnimationFrame);
            Player.OnCreatBody(World, PhysicConnectManager);
            Player.BodyPosiotion = new Vector2(240, 600);
            Player.OnShowAttackMessageEvent += OnPlayerShowAttackMessage;
            Player.OnLifeTimeZeroingEvent += SendLoseMessage;
            Player.OnLifeTimeZeroedEvent += OnLoseEvent;
            this.Attach(Player);

            bar = new StatusBar();
            bar.OnLoad();
            bar.Position = new Vector2(10, 10);
            Attach(bar);
            bar.SpeedBar.Full = fullLife;
            bar.SpeedBar.Value = fullLife;

            switch (Game1.stageManager.GameSrate.CurrentPlayer)
            {
                case Constants.PlayerId.Phi:
                    Player.Attack_Type = SingleGamePlayer.AttackType.Fire;
                    bar.Property = Constants.Property.Fire;
                    break;
                case Constants.PlayerId.Theta:
                    Player.Attack_Type = SingleGamePlayer.AttackType.Water;
                    bar.Property = Constants.Property.Water;
                    break;
                case Constants.PlayerId.Omega:
                    Player.Attack_Type = SingleGamePlayer.AttackType.Wind;
                    bar.Property = Constants.Property.Wind;
                    break;
            }
            switch (Game1.stageManager.GameSrate.PlayerSpinningType)
            {
                case Constants.SpinningType.Phi:
                    Player.Style = 0;
                    break;
                case Constants.SpinningType.Theta:
                    Player.Style = 2;
                    break;
                case Constants.SpinningType.Omega:
                    Player.Style = 3;
                    break;
                case Constants.SpinningType.India:
                    Player.Style = 4;
                    break;
                case Constants.SpinningType.Russia:
                    Player.Style = 5;
                    break;
                case Constants.SpinningType.Tiawan:
                    Player.Style = 6;
                    break;
            }
           

            Enemy = new BattlePlayer();
            Enemy.textureName = "spinning";
            Enemy.OnLoad();
            Enemy.LifeTime = enemyFullLife;
            Enemy.SetAnimation(Constants.playerAnimationFrame);
            Enemy.OnCreatBody(World, PhysicConnectManager);
            Enemy.BodyPosiotion = new Vector2(240, 200);
            Enemy.OnShowAttackMessageEvent += OnEnemyShowAttackMessage;
            Enemy.OnLifeTimeZeroedEvent += OnWinEvent;
            this.Attach(Enemy);
            switch (Game1.stageManager.BattleData.CurrentEnemy)
            {
                case Constants.PlayerId.Phi:
                    Enemy.Attack_Type = SingleGamePlayer.AttackType.Fire;
                    break;
                case Constants.PlayerId.Theta:
                    Enemy.Attack_Type = SingleGamePlayer.AttackType.Water;
                    break;
                case Constants.PlayerId.Omega:
                    Enemy.Attack_Type = SingleGamePlayer.AttackType.Wind;
                    break;
            }

            switch (Game1.stageManager.BattleData.EnemySpinningType) 
            {
                case Constants.SpinningType.Phi:
                    Enemy.Style = 0;
                    break;
                case Constants.SpinningType.Theta:
                    Enemy.Style = 2;
                    break;
                case Constants.SpinningType.Omega:
                    Enemy.Style = 3;
                    break;
                case Constants.SpinningType.India:
                    Enemy.Style = 4;
                    break;
                case Constants.SpinningType.Russia:
                    Enemy.Style = 5;
                    break;
                case Constants.SpinningType.Tiawan:
                    Enemy.Style = 6;
                    break;
            }

            EnemyBar bossBar = new EnemyBar(Enemy);
            bossBar.OnLoad();
            bossBar.SpeedBar.Full = Enemy.LifeTime;
            bossBar.SpeedBar.Value = Enemy.LifeTime;
            bossBar.Position = new Vector2(-70, -90);
            Enemy.Attach(bossBar);

            StageItemListBar silb = new StageItemListBar(Player, Enemy);
            silb.OnLoad();
            silb.Position = new Vector2(100);
            this.Attach(silb);

            

            te = new TextEntity();
            ResourceManager.ContentRoot = "";
            te.fontString = "TestFont";
            te.OnLoad();
            te.Origin = new Vector2(0.5f);
            te.Position = new Vector2(200, 200);
            te.Color = Color.Blue;
            te.Alpha = 0;
            te.ZIndex = Constants.debugText;
            Attach(te);

            b = new WindowBound();
            //b.OnLoad();
            b.OnCreatBound(World);
            this.Attach(b);

            _packetInfo = "hostId:" + Game1.hostId + ",clientId:" + Game1.clientId + ",isHost:" + Game1.stageManager.IsHost + ",";

            this.Channel = new UdpAnySourceMulticastChannel(IPAddress.Parse("224.0.1.100"), 3000);
            this.Channel.AfterOpen += new EventHandler(Channel_AfterOpen);
            this.Channel.BeforeClose += new EventHandler(Channel_BeforeClose);
            this.Channel.PacketReceived += new EventHandler<UdpPacketReceivedEventArgs>(Channel_PacketReceived);

            this.Channel.Open();
        }

        void OnPlayerShowAttackMessage(string s) 
        {
            this.Channel.Send(_packetInfo + "playerAttackMessage:{0},", s);
        }

        void OnEnemyShowAttackMessage(string s)
        {
            this.Channel.Send(_packetInfo + "enemyAttackMessage:{0},", s);
        }

        void Channel_BeforeClose(object sender, EventArgs e)
        {
            this.Channel.Send("END,{0}, leaves the UDP Multicast chat,", Game1.hostId);
        }

        void Channel_AfterOpen(object sender, EventArgs e)
        {
            this.Channel.Send("BEGIN,{0}, enters the UDP Multicast chat,", Game1.hostId);
        }

        //沒用到Channel.close(); 範例也沒
        int tempCounter;

        void Channel_PacketReceived(object sender, UdpPacketReceivedEventArgs e)
        {
            string[] temp;
            string[] temp1;

            temp = e.Message.Split(',');

            NoKeyFoundDictionary dataDictionary = new NoKeyFoundDictionary();

            bool partyFlag = false;

            for (int i = 0; i < temp.Length; i++)
            {
                temp1 = temp[i].Split(':');
                if (temp1.Length >= 2)
                    dataDictionary.Add(temp1[0], temp1[1]);
            }



            if (dataDictionary.Get("hostId") == Game1.hostId && dataDictionary.Get("clientId") == Game1.clientId && dataDictionary.Get("isHost") == "False") //client 來的封包
            {
                partyFlag = true;
            }
            else
            {
                partyFlag = false;
            }

            if (partyFlag)
            {
                if (dataDictionary.Get("updateMode") == "True")
                {
                    _accelReadingEnemy.X = float.Parse(dataDictionary.Get("accX"));
                    _accelReadingEnemy.Y = float.Parse(dataDictionary.Get("accY"));
                    _accelReadingEnemy.Z = float.Parse(dataDictionary.Get("accZ"));
                    Enemy.Accelerometer = _accelReadingEnemy;
                }

                if (dataDictionary.Get("enemyUseItemMessage")!="noKey") 
                {
                    switch (dataDictionary.Get("enemyUseItemMessage")) 
                    {
                        case "Marble":  //0
                            Player.MinusLifeTime(10);
                            break;
                        case "Sandbag": //1
                            Player.MinusLifeTime(20);
                            break;
                        case "Copter":  //2
                            Enemy.AddLifeTime(10);
                            break;
                        case "Windmill"://3
                            Enemy.AddLifeTime(20);
                            break;
                        case "Doll":    //4
                            Enemy.AddLifeTime(30);
                            break;
                    }
                }

                tempCounter++;
                te.Value = "Count:" + tempCounter;
                //te.Value = "X:" + _accelReadingEnemy.X + ", Y:" + _accelReadingEnemy.Y + ", Z:" + _accelReadingEnemy.X;
            }
        }

        int tempTimer = 0, _gameTime = 0, SceneTimer;
        protected override void UpdateSelf(GameTime gameTime)
        {
            base.UpdateSelf(gameTime);
            World.Step(1f / 60, 10, 10);
            PhysicConnectManager.OnUpdate(gameTime);

            Player.Accelerometer = _accelReading;
            bar.SpeedBar.Value = Player.LifeTime;

            int delta = gameTime.ElapsedGameTime.Milliseconds;
            tempTimer += delta;
            if (tempTimer / 50 >= 1)
            {
                tempTimer = tempTimer % 50;
                this.Channel.Send(_packetInfo + "playerPosX:{0},playerPosY:{1},enemyPosX:{2},enemyPosY:{3},playerLife:{4},enemyLife:{5},playerMoveType:{6},enemyMoveType:{7},updateMode:True,", Player.Position.X, Player.Position.Y, Enemy.Position.X, Enemy.Position.Y, Player.LifeTime, Enemy.LifeTime, Player.CurrentSpinningType, Enemy.CurrentSpinningType);
                //this.Channel.Send("hostId:{0},clientId:{1},playerPosX:{2},playerPosY:{3},enemyPosX:{4},enemyPosY:{5},isHost:True,", Game1.hostId, Game1.clientId, Player.Position.X, Player.Position.Y, Enemy.Position.X, Enemy.Position.Y);
                //this.Channel.Send("{0},{1},{2},{3},{4},", Game1.hostId, Player.Position.X, Player.Position.Y, Enemy.Position.X, Enemy.Position.Y);
            }
            _gameTime += delta;
            if (_gameTime / 1000 >= 1)
            {
                _gameTime = _gameTime % 1000;
                SceneTimer++;
            }
        }

        public void SendWinMessage()
        {
            this.Channel.Send(_packetInfo + "isLose:{0},", true);
        }

        public void OnWinEvent()
        {
            Game1.stageManager.stageScoreData.isWin = true;
            Game1.stageManager.stageScoreData.isBossStage = false;
            Game1.stageManager.stageScoreData.isBattle = true;
            Game1.stageManager.stageScoreData.Speed = Player.LifeTime;
            Game1.stageManager.stageScoreData.Time = SceneTimer;
            Game1.stageManager.stageScoreData.Bouns = 200;
            this.Channel.Send(_packetInfo + "isWin:{0},Speed:{1},Time:{2},Bouns:{3},", false, 0, 0, 10);
            OnEndCondition();
        }

        public void SendLoseMessage() 
        {
            this.Channel.Send(_packetInfo + "isLose:{0},", false);
        }

        public void OnLoseEvent()
        {
            Game1.stageManager.stageScoreData.isWin = false;
            Game1.stageManager.stageScoreData.isBossStage = false;
            Game1.stageManager.stageScoreData.isBattle = true;
            Game1.stageManager.stageScoreData.Speed = 0;
            Game1.stageManager.stageScoreData.Time = 0;
            Game1.stageManager.stageScoreData.Bouns = 10;
            this.Channel.Send(_packetInfo + "isWin:{0},Speed:{1},Time:{2},Bouns:{3},", true, Enemy.LifeTime, SceneTimer, 200);
            OnEndCondition();
        }

        public void OnEndCondition()
        {
            Game1.stageManager.GoToScene("reward");
        }

        public override BaseScene Clone()
        {
            BaseScene scene = new HostScene();
            scene.Size = new Vector2(Constants.Window_Width, Constants.Window_Height);
            scene.OnLoad();
            scene.SortChildren();
            return scene;
        }
    }
}
